package com.bocloud.cmp.service.resource;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bocloud.cmp.common.cache.DictionaryCache;
import com.bocloud.cmp.dao.BeanDetailDao;
import com.bocloud.cmp.dao.DataCenterDao;
import com.bocloud.cmp.dao.RackDao;
import com.bocloud.cmp.dao.RoomDao;
import com.bocloud.cmp.dao.ServerDao;
import com.bocloud.cmp.entity.resource.DataCenter;
import com.bocloud.cmp.entity.resource.Rack;
import com.bocloud.cmp.entity.resource.Room;
import com.bocloud.cmp.entity.resource.Server;
import com.bocloud.cmp.interfaces.resource.RoomService;
import com.bocloud.cmp.model.RoomBean;
import com.bocloud.cmp.model.Scope;
import com.bocloud.cmp.service.utils.ParamHelper;
import com.bocloud.common.enums.BaseStatus;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;

/**
 * 机房抽象Service接口实现类
 * 
 * @author wei wei
 * @version 1.0
 * @since 2016.02.27
 */
@Service("roomService")
public class RoomServiceImpl implements RoomService {

	private static Logger logger = LoggerFactory.getLogger(RoomServiceImpl.class);
	@Autowired
	private DataCenterDao dataCenterDao;
	@Autowired
	private RoomDao roomDao;
	@Autowired
	private RackDao rackDao;
	@Autowired
	private ServerDao serverDao;
	@Autowired
	private BeanDetailDao beanDetailDao;
	@Autowired
	private LockFactory lockFactory;

	@Override
	public BsmResult create(Room room, Long userId) {
		try {
			Integer total = 0;
			DataCenter center = this.dataCenterDao.query(room.getDcId());
			if (null == center) {
				return new BsmResult(false, "数据中心不存在");
			}
			if (StringUtils.isNotEmpty(center.getUsed())) {
				total = Integer.valueOf(center.getTotalArea()) - Integer.valueOf(center.getUsed());
			} else {
				total = Integer.valueOf(center.getTotalArea());
			}
			if (Integer.valueOf(room.getTotalArea()) > total) {
				return new BsmResult(false, "机房面积不可大于未使用的数据中心面积");
			}
			room.setCreaterId(userId);
			room.setMenderId(userId);
			room.setStatus(BaseStatus.NORMAL.name());
			roomDao.save(room);
			center.setUsed(String
					.valueOf(Integer.valueOf(room.getTotalArea()) + (Integer.valueOf(center.getTotalArea()) - total)));
			dataCenterDao.update(center);
		} catch (Exception e) {
			logger.error("Create room fail:", e);
			return new BsmResult(false, "添加失败", "", "");
		}
		return new BsmResult(true, room, "添加成功");
	}

	@Override
	public BsmResult modify(RoomBean bean, Long userId) {
		String path = Room.class.getSimpleName() + "_" + bean.getId();
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}

			Room room = this.roomDao.query(bean.getId());
			if (null == room) {
				logger.warn("Room does not exist!");
				return new BsmResult(false, "数据不存在", "", "");
			}

			DataCenter center = this.dataCenterDao.query(bean.getDcId());
			Integer total = Integer.valueOf(center.getTotalArea()) - Integer.valueOf(center.getUsed())
					+ Integer.valueOf(room.getTotalArea());
			if (Integer.valueOf(bean.getTotalArea()) > total) {
				return new BsmResult(false, "机房面积不可大于未使用的数据中心面积");
			}
			/*
			 * BsmResult result = this.checkRange(bean.getId(),
			 * bean.getRowNum(), bean.getRowNum()); if (!result.isSuccess()) {
			 * return result; }
			 */
			Integer roomArea = Integer.valueOf(room.getTotalArea());
			BeanUtils.copyProperties(bean, room);
			room.setMenderId(userId);
			this.roomDao.update(room);
			center.setUsed(String
					.valueOf(Integer.valueOf(center.getUsed()) + Integer.valueOf(room.getTotalArea()) - roomArea));
			dataCenterDao.update(center);
			return new BsmResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify room fail:", e);
			return new BsmResult(false, "修改失败", null, null);
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult remove(Long id, Long userId) {
		String path = Room.class.getSimpleName() + "_" + id;
		int countRack = 0;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时");
			}

			Room object = this.roomDao.query(id);
			if (null == object) {
				logger.warn("Room does not exist!");
				return new BsmResult(false, "数据不存在", "", "");
			}

			Map<String, Object> map = MapTools.simpleMap(Common.ROOM, id);
			countRack = this.rackDao.count(ParamHelper.getParams(map, Sign.EQ));
			if (countRack > 0) {
				logger.warn("Remove fail：have racks");
				return new BsmResult(false, "删除失败：该机房下存在机柜，无法删除", "", "");
			}

			boolean result = this.roomDao.remove(id, userId);
			if (result) {
				DataCenter center = dataCenterDao.query(object.getDcId());
				center.setUsed(
						String.valueOf(Integer.valueOf(center.getUsed()) - Integer.valueOf(object.getTotalArea())));
				dataCenterDao.update(center);
				return new BsmResult(true, "删除成功");
			}
			logger.info("Room has been removed");
			return new BsmResult(true, "已被删除");
		} catch (Exception e) {
			logger.error("Remove room fail:", e);
			return new BsmResult(false, "删除失败", null, null);
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult basic(Long id) {
		Room room = null;
		try {
			room = this.beanDetailDao.getRoomBean(id);
			if (null == room) {
				logger.warn("Room does not exist!");
				return new BsmResult(false, room, "该机房不存在");
			}
			room.setTypeName(DictionaryCache.readCache(room.getType()));
		} catch (Exception e) {
			logger.error("Query room fail:", e);
			return new BsmResult(false, "", null, null);
		}
		return new BsmResult(true, room, "查询成功");
	}

	@Override
	public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
		List<Room> list = null;
		List<SimpleBean> beans = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			total = this.roomDao.count(params);
			if (simple) {
				beans = this.roomDao.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = this.roomDao.list(page, rows, params, sorter);
				List<Room> rooms = new ArrayList<Room>();
				for (Room room : list) {
					room.setTypeName(DictionaryCache.readCache(room.getType()));
					List<Rack> racks = rackDao.listFree(room.getId());
					if (racks == null || racks.size() == 0) {
						room.setRacks(0);
						room.setServers(0);
						rooms.add(room);
					} else {
						room.setRacks(racks.size());
						for (Rack rack : racks) {
							room.setServers(serverDao.listByRack(rack.getId()).size());
						}
						rooms.add(room);
					}
				}
				gridBean = GridHelper.getBean(page, rows, total, rooms);
			}
			return new BsmResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query room list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
	}

	@Override
	public BsmResult listRacks(int page, int rows, List<Param> params, Map<String, String> sorter) {
		List<Rack> list = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			list = this.rackDao.list(page, rows, params, sorter);
			total = this.rackDao.count(params);
			gridBean = GridHelper.getBean(page, rows, total, list);
		} catch (Exception e) {
			logger.error("Query rack list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, gridBean, "查询成功");
	}

	@Override
	public BsmResult detail(Long id) {
		Room room = null;
		try {
			if (id == 0) {
				room = new Room();
				room.setRooms(this.roomDao.count(null));
				room.setRacks(this.rackDao.count(null));
				room.setServers(this.serverDao.count(null));
			} else {
				room = this.beanDetailDao.getRoomBean(id);
				if (null == room) {
					logger.warn("Room does not exist!");
					return new BsmResult(true, room, "该机房不存在");
				}
				room.setTypeName(DictionaryCache.readCache(room.getType()));
				Map<String, Object> roomMap = MapTools.simpleMap(Common.ROOM, id);
				List<Rack> rackList = this.rackDao.list(1, Integer.MAX_VALUE, ParamHelper.getParams(roomMap, Sign.EQ),
						null);
				int servers = 0;
				if (null != rackList && !rackList.isEmpty()) {
					Map<String, Object> rackMap = new HashMap<String, Object>();
					for (Rack rack : rackList) {
						rackMap.put(Common.RACK, rack.getId());
						servers = servers + this.serverDao.count(ParamHelper.getParams(rackMap, Sign.EQ));
					}
				}
				room.setRacks(this.rackDao.count(ParamHelper.getParams(roomMap, Sign.EQ)));
				room.setServers(servers);
			}
		} catch (Exception e) {
			logger.error("Query room detail fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, room, "查询成功");
	}

	@Override
	public BsmResult inDC(Long id, Long dcId, Long userId) {
		String path = Room.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.roomDao.belong(id, dcId, userId);
			return new BsmResult(true, "添加成功");
		} catch (Exception e) {
			logger.error("Join room to data center fail:", e);
			return new BsmResult(false, "添加失败", "", "");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult outDC(Long id, Long userId) {
		String path = Room.class.getSimpleName() + "_" + id;
		HarmonyLock lock = null;
		try {
			lock = lockFactory.getLock(path);
			if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
				logger.warn("Get harmonyLock time out!");
				return new BsmResult(false, "请求超时", "", "");
			}
			this.roomDao.release(id, userId);
			return new BsmResult(true, "移除成功");
		} catch (Exception e) {
			logger.error("Remove room from data center fail:", e);
			return new BsmResult(false, "移除失败", "", "");
		} finally {
			if (null != lock) {
				lock.release();
			}
		}
	}

	@Override
	public BsmResult freeRooms() {
		List<Room> list = null;
		try {
			list = this.roomDao.listFree();
		} catch (Exception e) {
			logger.error("Query free room list fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	public BsmResult checkRange(Room room, Integer rowNum, Integer colNum) {
		try {
			if (rowNum < 0 || colNum < 0) {
				logger.warn("Can not be less than 0");
				return new BsmResult(false, "行数或列数不能小于0");
			}

			if (rowNum >= room.getRowNum() && colNum >= room.getColNum()) {
				return new BsmResult(true, "范围可以变动");
			}

			Scope scope = this.rackDao.range(room.getId());
			if (null == scope) {
				return new BsmResult(true, "范围可以变动");
			}

			if (scope.getRow() > rowNum) {
				logger.warn("Scope does not meet the conditions!");
				return new BsmResult(false, "当前行数小于机柜所在的最大行数，行数建议值为" + (scope.getRow() + 1) + "行");
			}

			if (scope.getCol() > colNum) {
				logger.warn("Scope does not meet the conditions!");
				return new BsmResult(false, "当前列数小于机柜所在的最大列数，列数建议值为" + (scope.getCol() + 1) + "列");
			}

			return new BsmResult(true, "范围可以变动");
		} catch (Exception e) {
			logger.error("Check room range fail:", e);
			return new BsmResult(false, "范围不可变动");
		}
	}

	@Override
	public BsmResult checkPoint(Long id, Integer axisX, Integer axisY) {
		try {
			Room room = this.roomDao.query(id);
			if (null == room) {
				logger.warn("Room does not exist!");
				return new BsmResult(true, "该机房不存在");
			}

			if (axisX > room.getRowNum()) {
				logger.warn("Rows beyond the scope!");
				return new BsmResult(false, "位置超出机房的行数范围，本机房具有" + room.getRowNum() + "行，" + room.getColNum() + "列");
			}

			if (axisY > room.getColNum()) {
				logger.warn("Cols beyond the scope!");
				return new BsmResult(false, "位置超出机房的列数范围，本机房具有" + room.getRowNum() + "行，" + room.getColNum() + "列");
			}

			Map<String, Object> map = MapTools.simpleMap(Common.ROOM, id);
			map.put(Common.X, axisX);
			map.put(Common.Y, axisY);
			boolean result = this.rackDao.exists(ParamHelper.getParams(map, Sign.EQ));
			if (result) {
				logger.warn("Point has rack!");
				return new BsmResult(false, "当前位置存在机柜！");
			}

			return new BsmResult(true, "可添加机柜");
		} catch (Exception e) {
			logger.error("Check room point fail:", e);
			return new BsmResult(false, "不可添加机柜", "", "");
		}
	}

	@Override
	public BsmResult freeNodes(Long id) {
		List<Server> list = null;
		try {
			list = this.serverDao.listFreeNode(id, Room.class);
		} catch (Exception e) {
			logger.error("Query free server list from room fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}

	@Override
	public BsmResult freeManagers(Long id) {
		List<Server> list = null;
		try {
			list = this.serverDao.listFreeManager(id, Room.class);
		} catch (Exception e) {
			logger.error("Query free server list from room fail:", e);
			return new BsmResult(false, "查询失败", null, null);
		}
		return new BsmResult(true, list, "查询成功");
	}
}
